import 'package:flutter/material.dart';

class SlidePowerButtonCtrl {
  late ValueChanged<bool> _valueChanged;
  late ValueGetter<bool> _valueGetter;

  bool get isOn => _valueGetter();

  void toggle(bool isOn) => _valueChanged(isOn);
}

class SlidePowerButton2 extends StatefulWidget {
  final double width;
  final double height;
  final SlidePowerButtonCtrl? ctrl;
  final Future<bool> Function(bool) onToggle;

  const SlidePowerButton2({
    super.key,
    this.width = 200,
    this.height = 60,
    this.ctrl,
    required this.onToggle,
  });

  @override
  State createState() => _SlidePowerButton2State();
}

class _SlidePowerButton2State extends State<SlidePowerButton2> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  // 触发比例
  final double _activationRatio = 1 / 3;

  //是否打开
  bool _isOn = false;

  //是否加载中
  bool _isLoading = false;
  late Duration _currentDuration = Duration(milliseconds: 300);

  // 计算可滑动范围
  double get _maxDragOffset => widget.width - widget.height;

  //执行开关的阈值
  double get _activationThreshold => widget.width * _activationRatio;

  @override
  void initState() {
    super.initState();
    widget.ctrl?._valueChanged = _handleExternalToggle;
    widget.ctrl?._valueGetter = () => _isOn;
    _controller = AnimationController(
      vsync: this,
      value: 0,
      // 最小值
      lowerBound: 0,
      // 最大值
      upperBound: _maxDragOffset,
    );
    _controller.addListener(() {
      if (_controller.isCompleted) {
        //还原动画时间
        _currentDuration = Duration(milliseconds: 300);
      }
    });
  }

  //直接开启或者关闭按钮
  void _handleExternalToggle(bool isOn) {
    //正在Loading 禁止操作
    if (_isLoading) return;
    if (isOn != _isOn) {
      _isOn = isOn;
      _animateToTarget(isOn ? _maxDragOffset : 0);
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  //处理滑动中
  void _handleDragUpdate(DragUpdateDetails details) {
    if (_isLoading) return;
    // 拖动时停止当前动画
    if (_controller.isAnimating) _controller.stop();
    final newValue = (_controller.value + details.delta.dx).clamp(0.0, _maxDragOffset);
    _controller.value = newValue;
  }

  //处理滑动结束
  void _handleDragEnd(DragEndDetails details) async {
    if (_isLoading) return;
    if (_controller.isAnimating) _controller.stop();
    final double velocity = details.primaryVelocity ?? 0;
    final bool oldOn = _isOn;
    bool desiredIsOn = _isOn;
    print("处理滑动结束，velocity=$velocity,value=${_controller.value}");
    // 判断滑动结果
    if (velocity.abs() > 100) {
      // 快速滑动
      desiredIsOn = velocity < 0 ? false : true;
    } else {
      // 慢速滑动
      if (_isOn) {
        if ((_maxDragOffset - _controller.value) > _activationThreshold) {
          desiredIsOn = false;
        }
      } else {
        if (_controller.value > _activationThreshold) {
          desiredIsOn = true;
        }
      }
    }
    final targetValue = desiredIsOn ? _maxDragOffset : 0;
    // 触发回调
    if (oldOn != desiredIsOn) {
      //加载中状态
      setState(() => _isLoading = true);
      //按钮移动到中间
      _animateToTarget(_maxDragOffset / 2);
      //等等外部结果
      final success = await widget.onToggle(desiredIsOn);
      //取消加载中
      setState(() => _isLoading = false);
      //设置结果
      if (success) {
        _isOn = desiredIsOn;
      }
      //动画到对应位置
      _animateToTarget(_isOn ? _maxDragOffset : 0);
      if (targetValue == _controller.value) {
        //状态不一致刷新UI
        setState(() {
          //强制刷新UI
        });
      }
    } else {
      //回到原位
      _animateToTarget(_isOn ? _maxDragOffset : 0);
    }
  }

  void _animateToTarget(double end) {
    if (end != _controller.value) {
      // 执行动画
      print("执行动画 start=${_controller.value},end=$end");
      // 计算动画时长（速度越大时长越短）
      final double distance = (end - _controller.value).abs();
      final double baseDuration = distance / _maxDragOffset * 500; // 基础时长
      final duration = baseDuration.clamp(150, 500);
      _currentDuration = Duration(milliseconds: duration.toInt());
      _controller.animateTo(
        end,
        duration: _currentDuration,
        curve: Curves.decelerate, // 使用减速曲线模拟惯性
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    print("当前build _dragPosition = ${_controller.value}");
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        final color = _isOn ? Colors.green : Colors.grey;
        return SizedBox(
          width: widget.width,
          height: widget.height,
          child: Stack(
            children: [
              //背景
              _TrackBackground(
                color: color,
                height: widget.height,
                isOn: _isOn,
              ),
              //可滑动按钮
              Positioned(
                left: _controller.value,
                top: 0,
                bottom: 0,
                child: _DragThumb(
                  size: widget.height,
                  color: color,
                  onDragUpdate: _handleDragUpdate,
                  onDragEnd: _handleDragEnd,
                  isOn: _isOn,
                  isLoading: _isLoading,
                ),
              )
            ],
          ),
        );
      },
    );
  }
}

// 背景轨道组件
class _TrackBackground extends StatelessWidget {
  final Color color;
  final double height;
  final bool isOn;

  const _TrackBackground({
    required this.color,
    required this.height,
    required this.isOn,
  });

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      width: double.infinity,
      height: double.infinity,
      duration: const Duration(milliseconds: 300),
      curve: Curves.easeOut,
      decoration: BoxDecoration(
        color: color.withValues(alpha: 0.35),
        borderRadius: BorderRadius.circular(height / 2),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Padding(
            padding: const EdgeInsets.only(left: 12),
            child: AnimatedOpacity(
              duration: const Duration(milliseconds: 200),
              opacity: isOn ? 1.0 : 0.0,
              child: const Text("OFF", style: TextStyle(color: Colors.red)),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(right: 12),
            child: AnimatedOpacity(
              duration: const Duration(milliseconds: 200),
              opacity: isOn ? 0.0 : 1.0,
              child: const Text("ON", style: TextStyle(color: Colors.green)),
            ),
          ),
        ],
      ),
    );
  }
}

// 可拖动按钮组件
class _DragThumb extends StatelessWidget {
  final double size;
  final Color color;
  final Function(DragUpdateDetails) onDragUpdate;
  final Function(DragEndDetails) onDragEnd;
  final bool isOn;
  final bool isLoading;

  const _DragThumb({
    required this.size,
    required this.color,
    required this.onDragUpdate,
    required this.onDragEnd,
    required this.isOn,
    required this.isLoading,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onHorizontalDragUpdate: onDragUpdate,
      onHorizontalDragEnd: onDragEnd,
      child: Material(
        elevation: 4,
        shape: CircleBorder(),
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 300),
          width: size,
          height: size,
          decoration: BoxDecoration(
            color: color,
            shape: BoxShape.circle,
          ),
          child: AnimatedSwitcher(
            duration: const Duration(milliseconds: 300),
            transitionBuilder: (child, animation) => ScaleTransition(
              scale: animation,
              child: FadeTransition(
                opacity: animation,
                child: child,
              ),
            ),
            child: isLoading
                ? const CircularProgressIndicator(
                    color: Colors.white,
                    strokeWidth: 2,
                  )
                : Icon(
                    key: ValueKey(isOn),
                    isOn ? Icons.power_settings_new : Icons.power_off,
                    size: size * 0.6,
                    color: Colors.white,
                  ),
          ),
        ),
      ),
    );
  }
}
